﻿using NUnit.Framework;
using Rhino.Mocks;

namespace Shape.Mvp.Tests.Unit
{
   public class TestSubject { }
   public class TestSubject2 { }
   public class TestSubject3 { }

   [TestFixture]
   public class EventManagerTests
   {
      private EventManager m_em;

      [SetUp]
      public void SetUp()
      {
         m_em = new EventManager();
      }

      [Test]
      public void Publish_NoSubscribers_NoPublishing()
      {
         m_em.Publish<TestSubject>(new TestSubject());
      }

      [Test]
      public void Publish_SingleSubscriber_SingleEventPublished()
      {
         IEventSubscriber<TestSubject> mockSubscriber = MockRepository.GenerateMock<IEventSubscriber<TestSubject>>();

         TestSubject subject = new TestSubject();

         mockSubscriber.Expect(x => x.HandleEvent(subject));

         m_em.AddSubscriber(mockSubscriber);
         m_em.Publish<TestSubject>(subject);

         mockSubscriber.VerifyAllExpectations();
      }

      [Test]
      public void Publish_MultipleSubscribersWithDifferentSubjects_MultipleEventsPublished()
      {
         IEventSubscriber<TestSubject> mockSubscriber = MockRepository.GenerateMock<IEventSubscriber<TestSubject>>();
         IEventSubscriber<TestSubject2> mockSubscriber2 = MockRepository.GenerateMock<IEventSubscriber<TestSubject2>>();
         IEventSubscriber<TestSubject3> mockSubscriber3 = MockRepository.GenerateMock<IEventSubscriber<TestSubject3>>();

         TestSubject subject = new TestSubject();
         TestSubject2 subject2 = new TestSubject2();
         TestSubject3 subject3 = new TestSubject3();

         mockSubscriber.Expect(x => x.HandleEvent(subject));
         mockSubscriber2.Expect(x => x.HandleEvent(subject2));
         mockSubscriber3.Expect(x => x.HandleEvent(subject3));

         m_em.AddSubscriber(mockSubscriber);
         m_em.AddSubscriber(mockSubscriber2);
         m_em.AddSubscriber(mockSubscriber3);

         m_em.Publish<TestSubject>(subject);
         m_em.Publish<TestSubject2>(subject2);
         m_em.Publish<TestSubject3>(subject3);

         mockSubscriber.VerifyAllExpectations();
         mockSubscriber2.VerifyAllExpectations();
         mockSubscriber3.VerifyAllExpectations();
      }

      [Test]
      public void Publish_MultipleSubscribersWithSameSubject_MultipleEventsPublished()
      {
         IEventSubscriber<TestSubject> mockSubscriber = MockRepository.GenerateMock<IEventSubscriber<TestSubject>>();
         IEventSubscriber<TestSubject> mockSubscriber2 = MockRepository.GenerateMock<IEventSubscriber<TestSubject>>();
         IEventSubscriber<TestSubject> mockSubscriber3 = MockRepository.GenerateMock<IEventSubscriber<TestSubject>>();

         TestSubject subject = new TestSubject();

         mockSubscriber.Expect(x => x.HandleEvent(subject));
         mockSubscriber2.Expect(x => x.HandleEvent(subject));
         mockSubscriber3.Expect(x => x.HandleEvent(subject));

         m_em.AddSubscriber(mockSubscriber);
         m_em.AddSubscriber(mockSubscriber2);
         m_em.AddSubscriber(mockSubscriber3);

         m_em.Publish<TestSubject>(subject);

         mockSubscriber.VerifyAllExpectations();
         mockSubscriber2.VerifyAllExpectations();
         mockSubscriber3.VerifyAllExpectations();
      }

      [Test]
      public void RemoveSubscriber_SingleSubscriber_NoPublishing()
      {
         IEventSubscriber<TestSubject> mockSubscriber = MockRepository.GenerateMock<IEventSubscriber<TestSubject>>();

         TestSubject subject = new TestSubject();

         m_em.AddSubscriber(mockSubscriber);
         m_em.RemoveSubscriber(mockSubscriber);
         
         m_em.Publish<TestSubject>(subject);

         mockSubscriber.AssertWasNotCalled(x => x.HandleEvent(subject));
      }

      [Test]
      public void RemoveSubscriber_NoSubscribers_NoAction()
      {
         IEventSubscriber<TestSubject> mockSubscriber = MockRepository.GenerateStub<IEventSubscriber<TestSubject>>();

         m_em.RemoveSubscriber(mockSubscriber);
      }
   }
}
